iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
JavaScript

QA 的 JavaScript 初心之路:30 天做出一個能玩的戰鬥小遊戲《勇者 vs 小怪》系列 第 2

Day02|變數與資料型別:寫程式前,先了解『規格』

  • 分享至 

  • xImage
  •  

今天的主題:變數與資料型別

Day 1 只跑通了環境,今天要碰真正的 JavaScript 語法——變數(variable)與資料型別(data type)。

let 是蛋糕胚,const 是岩石

JavaScript 宣告變數常用兩個關鍵字:

let hp = 100;             // 之後可以改
const heroName = "勇者";   // 宣告後不能再改

想了一下要怎麼記住這兩個的差別,我覺得:let 像一塊蛋糕胚,之後想怎麼塗改、拆解都可以;const 像一塊岩石,一旦放定了就不能被撼動。

hp(血量)這種之後會一直變動的資料,適合用 let;heroName(角色名字)這種通常不會再變的資料,適合用 const

插入 day2-1.png:VS Code 裡宣告 let/const 的程式碼畫面

如果對 const 亂來,會發生什麼事?——兩種不一樣的失敗

這裡我特地測試了兩種情況,因為我發現它們的行為完全不同。

情況一:重複宣告同一個 const

const heroName = "勇者";
const heroName = "新生兒";

這會產生 SyntaxError(語法錯誤):Identifier 'heroName' has already been declared

關鍵是:JavaScript 會先把整份程式碼「讀一遍」確認語法都合法,才開始真正執行。所以這個錯誤不是「跑到那行才失敗」,而是整支程式從頭到尾都不會執行,連前面沒問題的程式碼也一起被拖累。

我把重新賦值(下面會講的情況二)跟重複宣告寫在同一支檔案裡測試,VS Code 對這兩種寫法的反應完全不同:重新賦值那行,編輯器沒有跳出任何警告;重複宣告那行,打字的當下就直接被畫上紅色波浪線,根本不用等執行。

插入 day2-2.png:VS Code 對兩種寫法的不同反應,重新賦值沒警告、重複宣告有紅色波浪線

情況二:重新賦值給 const

const heroName = "勇者";
heroName = "初心者";

理論上這會產生 TypeError(型別錯誤):Assignment to constant variable.,而且是執行到那一行的當下才會發生,跟情況一「還沒開始跑就整個失敗」不一樣。

但實際測試時,我發現一件更有意思的事:我根本沒看到這個 TypeError 出現過。

插入 day2-2-2.png:Console 只顯示 SyntaxError,沒有 TypeError

因為我的測試檔案裡,重新賦值(情況二)跟重複宣告(情況一)同時存在,而重複宣告是語法錯誤,在「讀一遍」的階段就被抓到——這代表整支程式根本沒有進入「執行」階段,連帶讓原本應該在執行到那一行才會噴出的 TypeError,根本沒有機會發生。我只看得到 SyntaxError,TypeError 被擋在前面,沒機會現身。這反而是「JavaScript 會先讀一遍全部程式碼才開始執行」這件事最直接的證明。

這會不會讓網頁跳出 404?

不會,而且我覺得這個問題本身很有意思。404 是瀏覽器層級的錯誤,代表「檔案根本找不到」,瀏覽器會整頁換成一個錯誤畫面。但 const 出錯是網頁已經載入成功之後,程式邏輯內部的問題——網頁畫面照樣顯示正常,只有打開 Console 才看得到這兩個錯誤訊息。這算是我今天釐清的一個誤會:網頁「打不開」和網頁「打開了但邏輯壞掉」,是完全不同層次的問題。

三大基本型別,和一個反直覺的例外

JavaScript 最常見的三種型別:

let hp = 100;          // number(數字)
let heroName = "勇者";  // string(字串)
let isAlive = true;    // boolean(布林,只有 true/false)

typeof 可以問 JavaScript「這是什麼型別」:

console.log(typeof hp);        // "number"
console.log(typeof heroName);  // "string"
console.log(typeof isAlive);   // "boolean"

我自己也跑了一個很多人會踩到的例外:

console.log(typeof null);

插入 day2-3.png:Console 裡 typeof null 印出 object

答案是 "object"——null 明明代表「空值」,卻被判定成物件型別,一開始看到我也愣了一下。查了才知道,這其實是 JavaScript 一個很有名的歷史包袱:1995 年 JS 剛誕生時的內部設計就把 null 判定成 object,官方後來也承認這是個失誤,但因為全世界已經有太多網站的程式碼依賴這個行為,修正它反而會讓大量既有網站壞掉,所以這個 bug 就這樣被永遠留著。這讓我想到 QA 工作裡常遇到的情況:有時候修一個已知的小 bug,風險比留著它不動還大。

順手查證一下:JS 不用先宣告型別,這件事該拿誰來對比?

寫這篇之前,我特地查證了一下「JS 不用像其他語言一樣先說明是整數/字串/布林」這個特性,實際上該拿誰來當對照組。查完發現:Python 同樣不用事先宣告型別,兩者都是「動態型別」語言,變數的型別是看塞了什麼值進去自動決定的。

真正需要「先宣告型別」的,是像 Java 這種「靜態型別」語言:

int hp = 100;         // 要先寫 int
String name = "勇者";  // 要先寫 String

所以正確的對照應該是「JS 和 Python 同一陣營(動態型別),Java 才是真正的對照組(靜態型別)」——這個對照組抓對了,之後理解為什麼有些語言要寫這麼多型別宣告,會更清楚。

小結

今天搞懂的事:

  • let 能改、const 不能改,但要記得「不能改」指的是不能重新賦值,之後學到物件時會有例外(先劇透一下)
  • 重複宣告 const 是語法錯誤,程式從頭到尾都不會跑;重新賦值 const 是執行期錯誤,跑到那行才會噴——而且如果兩者同時存在,語法錯誤會先擋下來,執行期錯誤根本沒機會出現
  • 網頁「載入失敗(404)」和「載入成功但邏輯出錯」是完全不同的兩件事
  • JS 和 Python 都不用事先宣告型別,兩者同一陣營;要拿來對比的該是 Java 這種靜態型別語言

明天繼續學字串與模板字串。


上一篇
Day01|寫下第一行 JavaScript,順便學會用 QA 的方式除錯
下一篇
Day03|字串與模板字串:蛋糕和岩石都能拿來拼
系列文
QA 的 JavaScript 初心之路:30 天做出一個能玩的戰鬥小遊戲《勇者 vs 小怪》7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言